package com.econ.powercloud.ems.service.biz;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.econ.powercloud.clickhouse.entity.EmsStatisticalDay;
import com.econ.powercloud.clickhouse.entity.EmsStatisticalMonth;
import com.econ.powercloud.clickhouse.entity.EmsStatisticalYear;
import com.econ.powercloud.common.base.facade.pojo.PageResult;
import com.econ.powercloud.ems.common.enums.CalculationDataMatchTypeTagEnum;
import com.econ.powercloud.ems.common.enums.DeviceType;
import com.econ.powercloud.ems.common.enums.ReportIdType;
import com.econ.powercloud.ems.common.util.DateTimeUtil;
import com.econ.powercloud.ems.constant.SysConstant;
import com.econ.powercloud.ems.dal.entity.*;
import com.econ.powercloud.ems.pojo.ApiDataVO;
import com.econ.powercloud.ems.pojo.ReportVO;
import com.econ.powercloud.ems.pojo.requestVO.ReportRequestVO;
import com.econ.powercloud.ems.service.dao.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author : zjf
 * @Description :电表报表 service
 * @Date : 2021/9/24 10:44
 * @Modified by : zjf
 */
@Service
public class ElectricMeterReportService {

    @Autowired
    private EmsDeviceDAO emsDeviceDAO;
    @Autowired
    private EmsColumnConfigDAO emsColumnConfigDAO;
    @Autowired
    private ClickHouseBizService clickHouseBizService;

    /**
     * 通过储能站id,储能装置id获取电表设备
     * 目前包含: 多功能电表,计量电表，设备电表
     * @param stationId: 储能站id
     */
    public PageResult<List<ApiDataVO>> getMeterList(String stationId, Integer pageNo, Integer pageSize){
        Page<EmsDevice> page = emsDeviceDAO.getPageByStationIdAndEquipmentIdAndDeviceTypes(stationId,null,
                Lists.newArrayList(DeviceType.MULTIFUNCTION_METER.getCode(), DeviceType.MEASURING_METER.getCode(),DeviceType.DEVICE_METER.getCode()),pageNo,pageSize);
        List<EmsDevice> deviceList = page.getRecords().stream().sorted(Comparator.comparing(EmsDevice::getDeviceType)).collect(Collectors.toList());
        List<ApiDataVO> apiDataVOS = Lists.newArrayList();
        for (EmsDevice emsDevice : deviceList) {
            apiDataVOS.add(ApiDataVO.builder().code(emsDevice.getDeviceCode()).name(emsDevice.getDeviceName()).build());
        }
        return PageResult.<List<ApiDataVO>>builder().data(apiDataVOS)
                .pageNo((int)page.getCurrent()).totalCount((int)page.getTotal()).build();
    }

    /**
     * 获取电表数据的 表头信息
     * @return
     */
    public List<ApiDataVO> getReportHeader(ReportRequestVO requestVO, List<EmsColumnConfig> columnList){
        if(requestVO.getReportId() == null){
            requestVO.setReportId(ReportIdType.METER.getCode());
        }
        List<ApiDataVO> reportHeader = Lists.newArrayList();
        //获取设备信息
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(requestVO.getDeviceCode());
        if(emsDevice == null){
            return reportHeader;
        }
        requestVO.setEquipmentId(emsDevice.getEnergyEquipmentId());
        requestVO.setStationId(emsDevice.getEnergyStationId());
        //获取该储能站,储能装置下的电表类型的设备有哪些列
        columnList.addAll(emsColumnConfigDAO.getListByCondition(requestVO.getStationId(),requestVO.getEquipmentId(),
                emsDevice.getDeviceType(),requestVO.getReportId()));
        if(CollectionUtils.isEmpty(columnList)){
            return reportHeader;
        }
        List<EmsColumnConfig> sortList = columnList.stream().sorted(Comparator.comparing(EmsColumnConfig::getSorting)).collect(Collectors.toList());
        sortList.stream().forEach(d->{
            reportHeader.add(ApiDataVO.builder().code(d.getColumnId()).name(d.getColumnName()).build());
        });
        //报表头部需要添加的日期这一列放在第一行
        reportHeader.add(0, ApiDataVO.builder().code(SysConstant.DATE).name(SysConstant.DATE_REMARK).build());
        return reportHeader;
    }

    /**
     * 获取电表日报表
     * 日报表是每个一个小时存一次数据,所以如果是当天的数据,需要重新计算最新一个小时的数据
     */
    public ReportVO getDataByDay(ReportRequestVO requestVO){
        requestVO.setEndTime(DateTimeUtil.getEndOfDay(new Date(requestVO.getStartTime())));
        ReportVO reportVO = ReportVO.builder().build();
        //该点号存放的需要展示列信息
        List<EmsColumnConfig> columnList = Lists.newArrayList();
        //获取报表头部信息
        List<ApiDataVO> reportHeader = this.getReportHeader(requestVO,columnList);
        if(CollectionUtils.isEmpty(reportHeader)){
            return reportVO;
        }
        reportVO.setReportHeader(reportHeader);
        //获取该时间段内报表数据
        List<Map<String,String>> bodyList = Lists.newArrayList();
//        List<EmsStatisticalDay> statisticalDayList = emsStatisticalDayDAO.getListByCondition(requestVO.getStationId(),requestVO.getEquipmentId(),
//                requestVO.getDeviceCode(),requestVO.getReportId(),requestVO.getStartTime(),requestVO.getEndTime());
        List<EmsStatisticalDay> statisticalDayList = clickHouseBizService.getDayDataByCondition(requestVO);
        if(CollectionUtils.isEmpty(statisticalDayList)){
            return reportVO;
        }
        //报表数据按照时间进行分组
        Map<Long,List<EmsStatisticalDay>> statisticalDayMap = statisticalDayList.stream().collect(Collectors.groupingBy(d->d.getTime()));
        statisticalDayMap = statisticalDayMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                (oleValue, newValue) -> oleValue, LinkedHashMap::new));
        statisticalDayMap.forEach((k,v)->{
            Map<String,String> map = Maps.newLinkedHashMap();
            //把日期那一列的数据放入
            map.put(SysConstant.DATE, DateTimeUtil.formatDate(new Date(k), DateTimeUtil.HOUR_PATTERN));
            Map<String, EmsStatisticalDay> dayMap = v.stream().collect(Collectors.toMap(EmsStatisticalDay::getColumnId, d->d,(p1, p2)->p1));
            reportHeader.stream().forEach(d->{
                EmsStatisticalDay emsStatisticalDay = dayMap.get(d.getCode());
                if(emsStatisticalDay != null){
                    map.put(emsStatisticalDay.getColumnId(),emsStatisticalDay.getVal());
                }
            });
            bodyList.add(map);
        });
        reportVO.setBodyList(bodyList);
        return reportVO;
    }

    /**
     * 获取电表月报表
     */
    public ReportVO getDataByMonth(ReportRequestVO requestVO){
        requestVO.setEndTime(DateTimeUtil.getEndOfMonth(new Date(requestVO.getStartTime())));
        ReportVO reportVO = ReportVO.builder().build();
        //该点号存放的需要展示列信息
        List<EmsColumnConfig> columnList = Lists.newArrayList();
        //获取报表头部信息
        List<ApiDataVO> reportHeader = this.getReportHeader(requestVO,columnList);
        if(CollectionUtils.isEmpty(reportHeader)){
            return reportVO;
        }
        reportVO.setReportHeader(reportHeader);
        List<EmsStatisticalMonth> statisticalMonthList = clickHouseBizService.getMonthDataByCondition(requestVO);
        if(CollectionUtils.isEmpty(statisticalMonthList)){
            return reportVO;
        }
        //获取该时间段内报表数据(区分一下报表的类型)
        List<Map<String,String>> bodyList = getMonthReportBodyList(statisticalMonthList,reportHeader);
        reportVO.setBodyList(bodyList);
        return reportVO;
    }

    /**
     * 获取电表年报表
     */
    public ReportVO getDataByYear(ReportRequestVO requestVO){
        requestVO.setEndTime(DateTimeUtil.getEndOfYear(new Date(requestVO.getStartTime())));
        ReportVO reportVO = ReportVO.builder().build();
        //该点号存放的需要展示列信息
        List<EmsColumnConfig> columnList = Lists.newArrayList();
        //获取报表头部信息
        List<ApiDataVO> reportHeader = this.getReportHeader(requestVO,columnList);
        if(CollectionUtils.isEmpty(reportHeader)){
            return reportVO;
        }
        reportVO.setReportHeader(reportHeader);
        List<EmsStatisticalYear> statisticalYearList = clickHouseBizService.getYearDataByCondition(requestVO);
        if(CollectionUtils.isEmpty(statisticalYearList)){
            return reportVO;
        }
        //获取该时间段内报表数据(区分一下报表的类型)
        List<Map<String,String>> bodyList = getYearReportBodyList(statisticalYearList,reportHeader);
        reportVO.setBodyList(bodyList);
        return reportVO;
    }

    /**
     * 获取上网/下网月报表
     */
    public ReportVO getOnOffGridDataByMonth(ReportRequestVO requestVO){
        if(requestVO.getEndTime() == null){
            requestVO.setEndTime(DateTimeUtil.getEndOfMonth(new Date(requestVO.getStartTime())));
        }
        requestVO.setReportId(ReportIdType.ON_OFF_GRID_ENERGY.getCode());
        ReportVO reportVO = ReportVO.builder().build();
        //该点号存放的需要展示列信息
        List<EmsColumnConfig> columnList = Lists.newArrayList();
        //获取报表头部信息
        List<ApiDataVO> reportHeader = this.getOnOffGridReportHeader(requestVO,columnList);
        reportVO.setReportHeader(reportHeader);
        List<EmsStatisticalMonth> statisticalMonthList = clickHouseBizService.getMonthDataByCondition(requestVO);
        if(CollectionUtils.isEmpty(statisticalMonthList)){
            return reportVO;
        }
        //获取该时间段内报表数据(区分一下报表的类型)
        List<Map<String,String>> bodyList = getMonthReportBodyList(statisticalMonthList,reportHeader);
        reportVO.setBodyList(bodyList);
        return reportVO;
    }

    /**
     * 获取上网/下网年报表
     */
    public ReportVO getOnOffGridDataByYear(ReportRequestVO requestVO){
        requestVO.setEndTime(DateTimeUtil.getEndOfYear(new Date(requestVO.getStartTime())));
        requestVO.setReportId(ReportIdType.ON_OFF_GRID_ENERGY.getCode());
        ReportVO reportVO = ReportVO.builder().build();
        //该点号存放的需要展示列信息
        List<EmsColumnConfig> columnList = Lists.newArrayList();
        //获取报表头部信息
        List<ApiDataVO> reportHeader = this.getOnOffGridReportHeader(requestVO,columnList);
        reportVO.setReportHeader(reportHeader);
        List<EmsStatisticalYear> statisticalYearList = clickHouseBizService.getYearDataByCondition(requestVO);
        if(CollectionUtils.isEmpty(statisticalYearList)){
            return reportVO;
        }
        //获取该时间段内报表数据(区分一下报表的类型)
        List<Map<String,String>> bodyList = getYearReportBodyList(statisticalYearList,reportHeader);
        reportVO.setBodyList(bodyList);
        return reportVO;
    }

    private List<Map<String,String>> getMonthReportBodyList(List<EmsStatisticalMonth> statisticalMonthList, List<ApiDataVO> reportHeader){
        List<Map<String,String>> bodyList = Lists.newArrayList();
        //报表数据按照时间进行分组
        Map<Long,List<EmsStatisticalMonth>> statisticalMonthMap = statisticalMonthList.stream().collect(Collectors.groupingBy(d->d.getTime()));
        statisticalMonthMap = statisticalMonthMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                (oleValue, newValue) -> oleValue, LinkedHashMap::new));
        statisticalMonthMap.forEach((k,v)->{
            Map<String,String> map = Maps.newLinkedHashMap();
            //把日期那一列的数据放入
            map.put(SysConstant.DATE, DateTimeUtil.formatDate(new Date(k), DateTimeUtil.DAY_PATTERN));
            Map<String, EmsStatisticalMonth> monthMap = v.stream().collect(Collectors.toMap(EmsStatisticalMonth::getColumnId, d->d,(p1, p2)->p1));
            reportHeader.stream().forEach(d->{
                EmsStatisticalMonth emsStatisticalMonth = monthMap.get(d.getCode());
                if(emsStatisticalMonth != null){
                    map.put(emsStatisticalMonth.getColumnId(),emsStatisticalMonth.getVal());
                }
            });
            bodyList.add(map);
        });
        return bodyList;
    }

    private List<Map<String,String>> getYearReportBodyList(List<EmsStatisticalYear> statisticalYearList,List<ApiDataVO> reportHeader){
        List<Map<String,String>> bodyList = Lists.newArrayList();
        //报表数据按照时间进行分组
        Map<Long,List<EmsStatisticalYear>> statisticalYearMap = statisticalYearList.stream().collect(Collectors.groupingBy(d->d.getTime()));
        statisticalYearMap = statisticalYearMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                (oleValue, newValue) -> oleValue, LinkedHashMap::new));
        statisticalYearMap.forEach((k,v)->{
            Map<String,String> map = Maps.newLinkedHashMap();
            //把日期那一列的数据放入
            map.put(SysConstant.DATE, DateTimeUtil.formatDate(new Date(k), DateTimeUtil.MONTH_PATTERN));
            Map<String, EmsStatisticalYear> yearMap = v.stream().collect(Collectors.toMap(EmsStatisticalYear::getColumnId, d->d,(p1, p2)->p1));
            reportHeader.stream().forEach(d->{
                EmsStatisticalYear emsStatisticalYear = yearMap.get(d.getCode());
                if(emsStatisticalYear != null){
                    map.put(emsStatisticalYear.getColumnId(),emsStatisticalYear.getVal());
                }
            });
            bodyList.add(map);
        });
        return bodyList;
    }

    /**
     * 获取上网/下网数据的 表头信息
     * @return
     */
    private List<ApiDataVO> getOnOffGridReportHeader(ReportRequestVO requestVO, List<EmsColumnConfig> columnList){
        if(requestVO.getReportId() == null){
            requestVO.setReportId(ReportIdType.ON_OFF_GRID_ENERGY.getCode());
        }
        List<ApiDataVO> reportHeader = Lists.newArrayList();
        //获取设备信息
        if( requestVO.getStationId() == null){
            return reportHeader;
        }
        //获取该储能站,储能装置下的电表类型的设备有哪些列
        columnList.addAll(emsColumnConfigDAO.getListByCondition(requestVO.getStationId(),requestVO.getEquipmentId(),
                null,requestVO.getReportId()));
        if(CollectionUtils.isEmpty(columnList)){
            return reportHeader;
        }
        List<EmsColumnConfig> sortList = columnList.stream().sorted(Comparator.comparing(EmsColumnConfig::getSorting)).collect(Collectors.toList());
        sortList.stream().forEach(d->{
            reportHeader.add(ApiDataVO.builder().code(d.getColumnId()).name(d.getColumnName()).build());
        });
        //报表头部需要添加的日期这一列放在第一行
        reportHeader.add(0, ApiDataVO.builder().code(SysConstant.DATE).name(SysConstant.DATE_REMARK).build());
        return reportHeader;
    }

}

